a11y(1.4.13): migrate saved-query nav tooltips to Tooltip primitive#3607
Conversation
Replaces the hand-rolled JS-positioned tooltip in saved-query-views.svelte and standalone-activities/saved-views.svelte with the Holocene Tooltip primitive (PR #3429). Each file previously maintained ~40 lines of custom state and DOM positioning logic (showTooltip, tooltipText, tooltipX/Y, positionTooltipFrom, onQueryBtnEnter/Move/Leave, use:portal floating <div>) that failed three SC 1.4.13 sub-criteria: - Dismissible: no Escape handler - Hoverable: pointer crossing the wrapper boundary fired onmouseleave before reaching the fixed <div>, dismissing the tooltip - ARIA: plain <div role="tooltip"> with no aria-describedby on the trigger The Tooltip primitive supplies all three: - Escape-to-dismiss via svelte:window keydown (dismissed flag auto-resets) - Hover bridge: 120 ms HOVER_HIDE_DELAY_MS lets the pointer transit onto the Portal-rendered popover; mouseenter on the popover cancels the hide timer - aria-describedby on the wrapper <div>; role="tooltip" + id on the popover hide={$savedQueryNavOpen} preserves the existing gate: tooltip is suppressed while the nav rail is expanded (full name already visible). usePortal delegates positioning to the Portal/Floating-UI integration, replacing the manual getBoundingClientRect arithmetic and also closing the 1.4.4 fixed-pixel-width gap on that surface. Net: ~80 lines removed across two files; no new lines of tooltip logic added. A11y-Audit-Ref: 1.4.13-saved-query-hand-rolled-tooltip Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
|
The latest updates on your projects. Learn more about Vercel for GitHub.
|
|
Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
Collapsed rail buttons render icon-only (name span is gated behind
$savedQueryNavOpen), leaving the <button> with no accessible name — SR
announces just "button". The tooltip conveys the label visually only.
Add aria-label={view.name} so the focusable button has a stable name in
both collapsed and expanded states.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
| class={merge( | ||
| 'h-4 w-4 flex-shrink-0 transition-colors duration-200', | ||
| $savedQueryNavOpen ? 'lg:hidden' : '', | ||
| 'flex w-full justify-start', |
There was a problem hiding this comment.
⚠️ 'view.count' is possibly 'undefined'.
| disabled={view.disabled} | ||
| size="sm" | ||
| > | ||
| <Icon |
There was a problem hiding this comment.
⚠️ 'view.count' is possibly 'undefined'.
The share button's "Share" text span is gated behind $savedQueryNavOpen, so a collapsed rail leaves only the copy icon and no accessible name. Add aria-label="Share" so it announces in both states. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Follow-up: accessible-name gap found during SR testingVoiceOver testing surfaced that in the collapsed (icon-only) rail, the buttons had no accessible name — SR announced just "button". The tooltip conveys the label visually only, and Pushed:
Save/Edit/New already render text (named); the chevron already has an |
The Escape handler was a bubble-phase window listener, so it never received the event when the tooltip trigger stopped keydown propagation (e.g. Holocene Button's on:keydown|stopPropagation). Keyboard Escape therefore failed to dismiss saved-query nav tooltips. Capture-phase runs before the target's stopPropagation, fixing dismissal for all Button-triggered Tooltip consumers. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
Auto-generated version bump from 2.52.0 to 2.52.1 Bump type: patch Changes included: - [`3be0df00`](3be0df0) fix(schedules): default absent second/minute/hour to 0 when editing (#3653) - [`508b65b7`](508b65b) fix(schedules): default emptied second/minute/hour to 0 on submit (#3655) - [`1f0e149c`](1f0e149) fix(workers): reject $LATEST qualifier in Lambda ARN validation (#3657) - [`b42b0776`](b42b077) a11y(2.4.3): inert-based focus containment + restore; drop trap from native dialogs (#3598) - [`cc491a29`](cc491a2) a11y(2.4.3): keep toast live region announcing during a focus trap [DT-4252] (#3654) - [`ddc7f8e2`](ddc7f8e) a11y(2.4.11): add scroll-padding so sticky overlays don't obscure focused elements (#3532) - [`b7e3a472`](b7e3a47) FilterBar icon update (#3660) - [`09318ec6`](09318ec) Add danger PR comment for api version bump (#3662) - [`273cc4be`](273cc4b) a11y(4.1.2): add label prop to Button primitive and enforce accessible names (#3556) - [`4507115f`](4507115) Use an editable combobox for the Cloud Run region field (DT-4232) (#3636) - [`694a7471`](694a747) a11y(1.4.13): migrate saved-query nav tooltips to Tooltip primitive (#3607) - [`8b384a40`](8b384a4) a11y(4.1.2): fix nested interactive elements in Copyable component (#3558) - [`1bfd2750`](1bfd275) fix describe SANO API requests to include runId parameter (#3661) - [`ba18b43e`](ba18b43) a11y(4.1.2): require label on CodeBlock primitive; add aria-readonly for read-only mode (#3557) - [`6e2290f1`](6e2290f) feat(deployments): make compute provider picker configurable (#3659) - [`4470b76a`](4470b76) fix(workers): persist WDV compute-config edits via update mask; revert $LATEST validation (#3658) - [`17fd591b`](17fd591) fix(nexus-operations): make start standalone nexus operation timeouts optional (#3656) Co-authored-by: rossedfort <11775628+rossedfort@users.noreply.github.com>
Summary
Replaces the hand-rolled JS-positioned tooltips in the saved-query nav rail (
saved-query-views.svelte) and standalone-activities saved-views rail (saved-views.svelte) with the HoloceneTooltipprimitive (PR #3429).Each file maintained ~40 lines of custom positioning state and DOM logic that failed three SC 1.4.13 sub-criteria:
svelte:windowkeydown handler;dismissedflag auto-resets on leaveonmouseleavebefore reaching theposition: fixeddivHOVER_HIDE_DELAY_MS+mouseenteron the popover cancels the hide timerfocusin/focusoutin primitiverole="tooltip"(4.1.2)<div role="tooltip">with noaria-describedbyon triggeraria-describedbyon wrapper,role="tooltip"+idon popoverNet change: ~80 lines removed across two files; 18 lines added (Tooltip wrapper + import).
What changed
src/lib/pages/saved-query-views.svelte: removedshowTooltip,tooltipText,tooltipX/Y,positionTooltipFrom,onQueryBtnEnter/Move/Leave, inlineportalfunction, and floating<div use:portal>. Replaced wrapper<div>inqueryButtonsnippet with<Tooltip text={…} right usePortal hide={$savedQueryNavOpen}>.src/lib/components/standalone-activities/saved-views.svelte: same migration;text={view.name}(no task-failures special-casing needed here).hide={$savedQueryNavOpen}preserves the existing gate: tooltip suppressed when the nav rail is expanded (full name already visible in the button label).usePortaldelegates positioning to the Portal/Floating-UI integration, replacing the manualgetBoundingClientRectarithmetic and also closing the 1.4.4 fixed-pixel-width/zoom gap on the same surface.Dependencies
right,usePortal, hover-bridge, Escape, andaria-describedbyto be available.Test plan
Keyboard:
dismissedauto-resets).Pointer:
Screen reader:
aria-describedby.Regression:
$savedQueryNavOpen = true(expanded rail): no tooltip appears.tabindex="-1"wrapper still skipped; inner<Button>is the focus stop.References
audit-output/issues/1.4.13-saved-query-hand-rolled-tooltip.mdA11y-Audit-Ref: 1.4.13-saved-query-hand-rolled-tooltip
🤖 Generated with Claude Code